using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Web;

using System.Xml;
using System.Xml.Xsl;
using System.Net.Mail;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (pty) ltd
	Author:		Alan Benington	
	Started:	2006-03-08	
	Status:		release	
	Version:	2.0.0
	Buidl:		20070524
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/

/*	-----------------------------------------------------------------------	
	Development Notes:
	==================
	20070425: 	Added overload to Send and formatMessage
	20070524:	Modification for .Net 2.0
	20071123:	Borrow features for EmailX.x_email - intention is that this
				class is deprecated in favour of EmailX.x_email
	-----------------------------------------------------------------------	*/

namespace umlungu.engineX.blogX {
	/// <summary>Type of email</summary>
	public enum x_emailtype {
		/// <summary>Text email</summary>
	    text = 1,
		/// <summary>Xml (text) email</summary>
	    xml = 2,
		/// <summary>Html email</summary>
	    html = 3
	}
	/// <summary>Separator type between form fields</summary>
	public enum x_emailfields {
		/// <summary>Text email</summary>
	    semicolon = 1,
		/// <summary>Xml (text) email</summary>
	    comma = 2,
		/// <summary>Html email</summary>
	    space = 3
	}
	/// <summary>
	/// Description of the x_email class.
	/// <para>This class is a utility class that formats messages for email and sends</para>
	/// <para>It does the formatting of following:</para>
	/// <para> - form fields to text</para>
	/// <para> - form fields to xml</para>
	/// <para> - form fields to html</para>
	/// <para> - </para>
	/// <para> - </para>
	/// <para> - </para>
	/// <para></para>
	/// </summary>
	public class x_email {
		#region Invisible properties
		private const string defaultTo = "customer@umlungu.com";
		private const string defaultFrom = "EngineX";
		private const string defaultSubject = "EngineX contact message";
		private string from;
		private x_config config;
		#endregion

		#region Visible properties
		private string to;
		/// <summary>The recipient of the email message</summary>
		/// <value>A string containg the recipient's email address</value>
		public string To {
			get { return to; }
			set { to = value; }
		}
		/// <summary>The sender of the email message</summary>
		/// <value>A string containg the sender's email address</value>
		public string From {
			get { return from; }
			set { from = value; }
		}
		private string cc;
		/// <summary>The email message cc addresses</summary>
		/// <value>A string containg the cc addresses of the email</value>
		public string Cc {
			get { return cc; }
			set { cc = value; }
		}
		private string bcc;
		/// <summary>The email message subject</summary>
		/// <value>A string containg the subject of the email</value>
		public string Bcc {
			get { return bcc; }
			set { bcc = value; }
		}
		private string subject;
		/// <summary>The email message subject</summary>
		/// <value>A string containg the subject of the email</value>
		public string Subject {
			get { return subject; }
			set { subject = value; }
		}
		private string message;
		/// <summary>The email message body</summary>
		/// <value>A string containg the body of the email - either text, xml or html</value>
		public string Message {
			get { return message; }
			set { message = value; }
		}
		private x_emailtype type;
		/// <summary>The type of email to be sent</summary>
		/// <value>An x_emailtype enumeration obejct</value>
		public x_emailtype Type {
			get { return type; }
			set { type = value; }
		}
		private XslCompiledTransform htmlTemplate;
		/// <summary></summary>
		/// <value></value>
		public XslCompiledTransform HtmlTemplate {
			get { return htmlTemplate; }
			set { htmlTemplate = value; }
		}
		private string server;
		/// <summary>The email message body</summary>
		/// <value>A string containg the body of the email - either text, xml or html</value>
		public string Server {
			get { return server; }
			set { server = value; }
		}
		#endregion

		#region Constructors/Destructors
		/// <overloads>Constructor</overloads>
		/// <summary>Default constructor - to, from, subject taken from configuration/defaults</summary>
		public x_email() {
			config = new x_config();
			type = x_emailtype.text;
			to = (config.EmailTo == null)? defaultTo : config.EmailTo;
			from = (config.EmailFrom == null)? defaultFrom : config.EmailFrom;
			subject = (config.EmailSubject == null)? defaultSubject : config.EmailSubject;
		}
		/// <summary>Constructor description</summary>
		/// <param name="emailTo">The email 'to' address</param>
		/// <param name="emailFrom">The email 'from' address</param>
		/// <param name="emailSubject">The email body</param>
		public x_email(string emailTo, string emailFrom, string emailSubject) {
			type = x_emailtype.text;
			to = emailTo;
			from = emailFrom;
			subject = emailSubject;
		}
		#endregion

		#region Public methods
		/// <overloads>Sends the email</overloads>
		/// <summary>Default. Assumes to, from, subject and message already set</summary>
		public void Send() {
			if (type == x_emailtype.xml || type == x_emailtype.text) {
				SmtpClient smtp = new SmtpClient();
				smtp.Send(from, to, subject, message);
			} else {
				Send(new MailMessage());
			}
		}
		/// <summary>MailMessage supplied (with attachments, if required). Assumes to, from, subject and message already set</summary>
		public void Send(MailMessage thisMail) {
			thisMail.From = new MailAddress(from);
			thisMail.To.Add(new MailAddress(to));
			thisMail.Subject = subject;
			thisMail.IsBodyHtml = (type == x_emailtype.xml || type == x_emailtype.text)? false : true;
			thisMail.Body = message;
			if (cc != null) {
				thisMail.CC.Add(new MailAddress(cc));
			}
			if (bcc != null) {
				thisMail.Bcc.Add(new MailAddress(bcc));
			}
			setSmtp().Send(thisMail);
		}
		/// <summary>Send a text message</summary>
		/// <param name="msg">The email message body</param>
		public void Send(string msg) {
			message = msg;
			Send();
		}
		/// <summary>Send the form fields defined in the request</summary>
		/// <param name="request">The http request object</param>
		public void Send(HttpRequest request) {
			message = formatMessage(request, null);
			Send();
		}
		/// <summary>Send the form fields defined in the request</summary>
		/// <param name="request">The http request object</param>
		/// <param name="template">The xsl template used to transform the xml to html</param>
		public void Send(HttpRequest request, XslCompiledTransform template) {
			message = formatMessage(request, template);
			Send();
		}
		/// <summary>Send the form fields defined in the request</summary>
		/// <param name="request">The http request object</param>
		/// <param name="fldformat">The fld format type to be used</param>
		public void Send(HttpRequest request, x_emailfields fldformat) {
			message = formatMessage(request, fldformat);
			Send();
		}
		/// <summary>Send the (transformed) xml document</summary>
		/// <param name="msgxml">The http request object</param>
		/// <param name="template">The xsl template used to transform the xml to html</param>
		public void Send(XmlDocument msgxml, XslCompiledTransform template) {
			message = formatMessage(msgxml, template);
			Send();
		}
		/// <summary>Send the (transformed) xml element</summary>
		/// <param name="msgxml">The message xml</param>
		/// <param name="template">The xsl template used to transform the xml to html</param>
		public void Send(XmlElement msgxml, XslCompiledTransform template) {
			message = formatMessage(msgxml, template);
			Send();
		}
		/// <summary>Send the (transformed) xml document with attachments</summary>
		/// <param name="msgxml">The http request object</param>
		/// <param name="template">The xsl template used to transform the xml to html</param>
		/// <param name="attachments">Concatenated list of attachment files (separated by '|')</param>
		public void Send(XmlDocument msgxml, XslCompiledTransform template, string attachments) {
			message = formatMessage(msgxml, template);
			MailMessage thisMail = new MailMessage();
			char[] delim = new char[] {'|'};
			foreach (string attachment in attachments.Split(delim)) {
				if (attachment != null && attachment != "") {
					thisMail.Attachments.Add(new Attachment(attachment));
				}
			}
			Send(thisMail);
		}
		/// <summary>Sends the xml using the xslt template</summary>
		/// <param name="xmlelem">The xml element</param>
		/// <param name="template">The xsl template</param>
		/// <param name="logfile">The file (full path) to write as a log</param>
		public void Send(XmlElement xmlelem, XslCompiledTransform template, string logfile) {
			type = x_emailtype.html;	// asume transform to html for now
			message = formatMessage(xmlelem, template);
			StreamWriter sr = File.CreateText(logfile);
			sr.Write(message);
			sr.Close();
			Send();
		}
		/// <summary>Sends the xml using the xslt template</summary>
		/// <param name="xmlelem">The xml element</param>
		/// <param name="template">The xsl template</param>
		/// <param name="arguments">The xsl template arguments</param>
		/// <param name="logfile">The file (full path) to write as a log</param>
		public void Send(XmlElement xmlelem, XslCompiledTransform template, XsltArgumentList arguments, string logfile) {
			type = x_emailtype.html;	// asume transform to html for now
			message = formatMessage(xmlelem, template, arguments);
			StreamWriter sr = File.CreateText(logfile);
			sr.Write(message);
			sr.Close();
			Send();
		}
		#endregion
		
		#region Protected methods
		#endregion
				
		#region Private methods
		/// <overloads>Format the message body for form submissions</overloads>
		/// <summary>Formats to xml or transformed to html</summary>
		/// <param name="request">The http request object</param>
		/// <param name="xslt">The xsl template</param>
		private string formatMessage(HttpRequest request, XslCompiledTransform xslt) {
			XmlDocument msgdoc = new XmlDocument();
			string msg = (type == x_emailtype.text)? "Form fields:" : "<form/>";
			if (type == x_emailtype.xml || type == x_emailtype.html)
				msgdoc.LoadXml(msg);
			String[] fldnames = request.Form.AllKeys;
			foreach (string fldname in fldnames)  {
				if (type == x_emailtype.text)
					msg = String.Concat(msg, "\n", fldname, ":\t", request.Form[fldname]);
				else {
					XmlElement fld = (XmlElement)msgdoc.DocumentElement.AppendChild(msgdoc.CreateElement("field"));
					fld.SetAttribute("name", fldname);
					fld.InnerText = request.Form[fldname];
				}
			}
			if (type != x_emailtype.text)
				msg = formatMessage(msgdoc, xslt);
			return msg;
		}
		/// <summary>Formats to xml or transformed to html</summary>
		/// <param name="msgdoc">The xml document</param>
		/// <param name="xslt">The xsl template</param>
		private string formatMessage(XmlDocument msgdoc, XslCompiledTransform xslt) {
			return formatMessage(msgdoc.DocumentElement, xslt);
		}
		/// <summary>Formats to xml or transformed to html</summary>
		/// <param name="msgel">The xml element</param>
		/// <param name="xslt">The xsl template</param>
		private string formatMessage(XmlElement msgel, XslCompiledTransform xslt) {
			return formatMessage(msgel, xslt, null);
		}
		/// <summary>Formats to xml or transformed to html</summary>
		/// <param name="msgel">The xml element</param>
		/// <param name="xslt">The xsl template</param>
		/// <param name="args">The xsl template arguments</param>
		private string formatMessage(XmlElement msgel, XslCompiledTransform xslt, XsltArgumentList args) {
			string msg = "";
			if (type == x_emailtype.xml)
				msg = msgel.OuterXml;
			else if (type == x_emailtype.html) {
				msg = transformMessage(msgel, xslt, args);
			} else
				msg = msgel.InnerText;
			return msg;
		}
		/// <summary>Formats to delimited text</summary>
		private string formatMessage(HttpRequest request, x_emailfields format) {
			string delim, msg = "";
			switch (format) {
				case x_emailfields.semicolon:	delim = ";";	break;
				case x_emailfields.space:		delim = " ";	break;
				case x_emailfields.comma:
				default:						delim = ",";	break;
			}
			String[] fldnames = request.Form.AllKeys;
			foreach (string fldname in fldnames)  {
				msg = String.Concat(msg, request.Form[fldname], delim);
			}
			return msg;
		}
		private string transformMessage(XmlElement msgel, XslCompiledTransform xslt) {
			return transformMessage(msgel, xslt, null);
		}
		private string transformMessage(XmlElement msgel, XslCompiledTransform xslt, XsltArgumentList args) {
			StringWriter writer = new StringWriter();
			xslt.Transform(msgel, args, writer);
			return writer.ToString();
		}
		private SmtpClient setSmtp() {
			SmtpClient smtp = new SmtpClient();
			if (server == null || server == "")	// if if not explicitly set, use config
				server = config.EmailHost;
			if (server != null && server != "")
				smtp.Host = server;
			smtp.Credentials = CredentialCache.DefaultNetworkCredentials;
			return smtp;
		}
		#endregion
	}
}
